package edu.bu.manateem.msg.util;

import java.util.Arrays;import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import edu.bu.manateem.msg.MSGConstants;

public class ChemicalFormulaUtils 
{
	private static final String[] ELEMENTS = {"C", "H", "N", "O", "S", "Na", "Mg"};
	private static final String CARBON = "C";
	private static final String HYDROGEN = "H";
	private static final String NITROGEN = "N";
	private static final String OXYGEN = "O";
	private static final String SULPHUR = "S";
	private static final String SODIUM = "Na";
	private static final String MAGNESIUM   = "Mg";
	
	private static final String SEARCH = "([A-Z])";
	private static final String REPLACE = "\t$1";


	/**
	 * Parses chemical formula.
	 * From Isotope Pattern Calculator
	 * @param formula
	 * @return
	 * @throws IllegalArgumentException
	 */
	public static HashMap<String, Integer> parseChemFormula(String formula) throws IllegalArgumentException 
	{
		HashMap<String, Integer> components = new HashMap<String, Integer>();
		String[] split = formula.replaceAll(SEARCH, REPLACE).trim().split(MSGConstants.TAB);

		for (String componentString : split) {
			int firstDigitIndex = -1;
			for (int i = 0; i < componentString.length(); i++) {
				if (Character.isDigit(componentString.charAt(i))) {
					firstDigitIndex = i;
					break;
				}
			}
			String symbol;
			int number = 1;
			if (firstDigitIndex == -1) {
				symbol = componentString;
			} else {
				symbol = componentString.substring(0, firstDigitIndex);
				number = new Integer(componentString.substring(firstDigitIndex));
			}
			addComponent(symbol, number, components);
		}
		return components;
	}

	/**
	 * 
	 * @param symbol
	 * @param number
	 * @param components
	 */
	public static void addComponent(String symbol, int number, HashMap<String, Integer> components) 
	{
		symbol = symbol.trim();
		if (symbol.equals(MSGConstants.EMPTY_STRING)) {
			return;
		}
		if (components.containsKey(symbol)) {
			components.put(symbol, components.get(symbol) + number);
		} else {
			components.put(symbol, number);
		}
	}

	/**
	 * Converts the shorthand [1,3,4,9,1]+0    [0,0,0,0,3]
	 * into proper chemical formula
	 * @param shorthand
	 * @param addExtraWater - an extra H2O will be added
	 * @return
	 */
	public static Map<String, Integer> getComponentsFromShorthand(String shorthand, boolean addExtraWater)
	{		
		Map<String, Integer> components = new HashMap<String, Integer>();
		// fill the map with 0s
		for (int i = 0; i < ELEMENTS.length; i++)
		{
			components.put(ELEMENTS[i], 0);
		}

		String[] subFormula = StringUtils.substringsBetween(shorthand, "[", "]");

		// 0 has the sugar
		// 1 has the addunct (presumably water as the last integer)

		String[] sugar = StringUtils.split(subFormula[0], ",");

		int carbons;
		int hydrogens;
		int oxygens;
		int nitrogens;
		int sulphurs;

		for (int i = 0; i < sugar.length; i++)
		{
			Integer mult = Integer.parseInt(sugar[i]);
			if (mult > 0)
			{

				switch(i)
				{
				case 0: //delta HexA
					components.put(CARBON, 6 * mult);
					components.put(HYDROGEN, 6 * mult);
					components.put(OXYGEN, 5 * mult);
					break;

				case 1: //HexA
					carbons = components.get(CARBON);
					hydrogens = components.get(HYDROGEN);
					oxygens = components.get(OXYGEN);

					components.put(CARBON, carbons + 6 * mult);
					components.put(HYDROGEN, hydrogens + 8 * mult);
					components.put(OXYGEN, oxygens + 6 * mult);
					break;

				case 2: //GlcN minus H2O
					carbons = components.get(CARBON);
					hydrogens = components.get(HYDROGEN);
					nitrogens = components.get(NITROGEN);
					oxygens = components.get(OXYGEN);

					components.put(CARBON, carbons + 6 * mult);
					components.put(HYDROGEN, hydrogens + 11 * mult);
					components.put(NITROGEN, nitrogens + 1 * mult);
					components.put(OXYGEN, oxygens + 4 * mult);
					break;

				case 3: //Ac
					carbons = components.get(CARBON);
					hydrogens = components.get(HYDROGEN);
					oxygens = components.get(OXYGEN);

					components.put(CARBON, carbons + 2 * mult);
					components.put(HYDROGEN, hydrogens + 2 * mult);
					components.put(OXYGEN, oxygens + 1 * mult);
					break;

				case 4: //SO3
					oxygens = components.get(OXYGEN);
					sulphurs = components.get(SULPHUR);

					components.put(OXYGEN, oxygens + 3 * mult);
					components.put(SULPHUR, sulphurs + 1 * mult);
					break;

				default:
					System.out.println("Cannot parse formula " + Arrays.toString(sugar).toString());
					break;
				}


				//				switch(i)
				//				{
				//				case 0:
				//					components.put(CARBON, 6 * mult);
				//					components.put(HYDROGEN, 6 * mult);
				//					components.put(OXYGEN, 5 * mult);
				//					break;
				//
				//				case 1:
				//					carbons = components.get(CARBON);
				//					hydrogens = components.get(HYDROGEN);
				//					oxygens = components.get(OXYGEN);
				//
				//					components.put(CARBON, carbons + 6 * mult);
				//					components.put(HYDROGEN, hydrogens + 8 * mult);
				//					components.put(OXYGEN, oxygens + 6 * mult);
				//					break;
				//
				//				case 2:
				//					carbons = components.get(CARBON);
				//					hydrogens = components.get(HYDROGEN);
				//					nitrogens = components.get(NITROGEN);
				//					oxygens = components.get(OXYGEN);
				//
				//					components.put(CARBON, carbons + 6 * mult);
				//					components.put(HYDROGEN, hydrogens + 11 * mult);
				//					components.put(NITROGEN, nitrogens + 1 * mult);
				//					components.put(OXYGEN, oxygens + 4 * mult);
				//					break;
				//
				//				case 3:
				//					oxygens = components.get(OXYGEN);
				//					sulphurs = components.get(SULPHUR);
				//
				//					components.put(OXYGEN, oxygens + 3 * mult);
				//					components.put(SULPHUR, sulphurs + 1 * mult);
				//					break;
				//
				//				case 4:
				//					carbons = components.get(CARBON);
				//					hydrogens = components.get(HYDROGEN);
				//					oxygens = components.get(OXYGEN);
				//
				//					components.put(CARBON, carbons + 2 * mult);
				//					components.put(HYDROGEN, hydrogens + 2 * mult);
				//					components.put(OXYGEN, oxygens + 1 * mult);
				//					break;
				//				default:
				//					System.out.println("Cannot parse formula " + sugar);
				//					break;
				//				}
			}
		}

		String[] extra = StringUtils.split(subFormula[1], ",");

		//		int numberOfAmmoniumMolecules = Integer.parseInt(extra[4]);
		//
		//		if (numberOfAmmoniumMolecules > 0)
		//		{
		//			nitrogens = components.get(NITROGEN);
		//			components.put(NITROGEN, nitrogens + numberOfAmmoniumMolecules);
		//
		//			hydrogens = components.get(HYDROGEN);
		//			components.put(HYDROGEN, hydrogens + numberOfAmmoniumMolecules * 3);
		//		}

		int numberOfAmmoniumMolecules = Integer.parseInt(extra[0]);
		if (numberOfAmmoniumMolecules > 0)
		{
			nitrogens = components.get(NITROGEN);
			components.put(NITROGEN, nitrogens + numberOfAmmoniumMolecules);

			hydrogens = components.get(HYDROGEN);
			components.put(HYDROGEN, hydrogens + numberOfAmmoniumMolecules * 3);
		}

		int numberofSodiumMolecules = Integer.parseInt(extra[1]);
		if (numberofSodiumMolecules > 0)
		{
			components.put(SODIUM, numberofSodiumMolecules);
		}

		int numberofMagnesiumMolecules = Integer.parseInt(extra[2]);
		if (numberofMagnesiumMolecules > 0)
		{
			components.put(MAGNESIUM, numberofMagnesiumMolecules);
		}


		// Finally Add Water
		if (addExtraWater)
		{
			hydrogens = components.get(HYDROGEN);
			components.put(HYDROGEN, hydrogens + 2);

			oxygens = components.get(OXYGEN);
			components.put(OXYGEN, oxygens + 1);
		}

		return components;
	}

	public static void main (String[] args)
	{
		Map<String, Integer> map = getComponentsFromShorthand("[0,4,5,2,6]     [2,2,2]", true);
		System.out.println(map);
	}
}
